postgrest.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import { useParams } from 'common'
  2. import dayjs from 'dayjs'
  3. import { ArrowRight, RefreshCw } from 'lucide-react'
  4. import { useEffect, useRef } from 'react'
  5. import ReportFilterBar from '@/components/interfaces/Reports/ReportFilterBar'
  6. import ReportHeader from '@/components/interfaces/Reports/ReportHeader'
  7. import ReportPadding from '@/components/interfaces/Reports/ReportPadding'
  8. import { REPORT_DATERANGE_HELPER_LABELS } from '@/components/interfaces/Reports/Reports.constants'
  9. import ReportStickyNav from '@/components/interfaces/Reports/ReportStickyNav'
  10. import { SharedAPIReport } from '@/components/interfaces/Reports/SharedAPIReport/SharedAPIReport'
  11. import { useSharedAPIReport } from '@/components/interfaces/Reports/SharedAPIReport/SharedAPIReport.constants'
  12. import {
  13. DatePickerValue,
  14. LogsDatePicker,
  15. } from '@/components/interfaces/Settings/Logs/Logs.DatePickers'
  16. import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt'
  17. import DefaultLayout from '@/components/layouts/DefaultLayout'
  18. import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout'
  19. import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
  20. import { ObservabilityLink } from '@/components/ui/ObservabilityLink'
  21. import { useRefreshHandler, useReportDateRange } from '@/hooks/misc/useReportDateRange'
  22. import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector'
  23. import type { NextPageWithLayout } from '@/types'
  24. const PostgRESTReport: NextPageWithLayout = () => {
  25. return (
  26. <ReportPadding>
  27. <PostgrestReport />
  28. </ReportPadding>
  29. )
  30. }
  31. PostgRESTReport.getLayout = (page) => (
  32. <DefaultLayout>
  33. <ObservabilityLayout title="PostgREST">{page}</ObservabilityLayout>
  34. </DefaultLayout>
  35. )
  36. export type UpdateDateRange = (from: string, to: string) => void
  37. export default PostgRESTReport
  38. const PostgrestReport = () => {
  39. const { db, chart } = useParams()
  40. const {
  41. selectedDateRange,
  42. datePickerValue,
  43. datePickerHelpers,
  44. showUpgradePrompt,
  45. setShowUpgradePrompt,
  46. handleDatePickerChange: handleDatePickerChangeFromHook,
  47. } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES)
  48. const {
  49. data,
  50. error,
  51. isLoading,
  52. refetch,
  53. isRefetching,
  54. filters,
  55. addFilter,
  56. removeFilters,
  57. isLoadingData,
  58. sql,
  59. } = useSharedAPIReport({
  60. filterBy: 'postgrest',
  61. start: selectedDateRange?.period_start?.date,
  62. end: selectedDateRange?.period_end?.date,
  63. })
  64. const state = useDatabaseSelectorStateSnapshot()
  65. const hasStateSyncedFromUrlRef = useRef(false)
  66. useEffect(() => {
  67. if (hasStateSyncedFromUrlRef.current) return
  68. hasStateSyncedFromUrlRef.current = true
  69. if (db !== undefined) {
  70. setTimeout(() => {
  71. // [Joshen] Adding a timeout here to support navigation from settings to reports
  72. // Both are rendering different instances of ProjectLayout which is where the
  73. // DatabaseSelectorContextProvider lies in (unless we reckon shifting the provider up one more level is better)
  74. state.setSelectedDatabaseId(db)
  75. }, 100)
  76. }
  77. if (chart !== undefined) {
  78. setTimeout(() => {
  79. const el = document.getElementById(chart)
  80. if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' })
  81. }, 200)
  82. }
  83. }, [state, db, chart])
  84. const handleDatePickerChange = (values: DatePickerValue) => {
  85. handleDatePickerChangeFromHook(values)
  86. }
  87. const onRefreshReport = useRefreshHandler(
  88. datePickerValue,
  89. datePickerHelpers,
  90. handleDatePickerChange,
  91. refetch
  92. )
  93. return (
  94. <>
  95. <ReportHeader showDatabaseSelector={false} title="Data API" />
  96. <ReportStickyNav
  97. content={
  98. <div className="flex flex-col gap-2">
  99. <div className="flex gap-2">
  100. <ButtonTooltip
  101. type="default"
  102. disabled={isRefetching}
  103. icon={<RefreshCw className={isRefetching ? 'animate-spin' : ''} />}
  104. className="w-7"
  105. tooltip={{ content: { side: 'bottom', text: 'Refresh report' } }}
  106. onClick={onRefreshReport}
  107. />
  108. <LogsDatePicker
  109. onSubmit={handleDatePickerChange}
  110. value={datePickerValue}
  111. helpers={datePickerHelpers}
  112. />
  113. <UpgradePrompt
  114. show={showUpgradePrompt}
  115. setShowUpgradePrompt={setShowUpgradePrompt}
  116. title="Report date range"
  117. description="Report data can be stored for a maximum of 3 months depending on the plan that your project is on."
  118. source="postgrestReportDateRange"
  119. />
  120. {selectedDateRange && (
  121. <div className="flex items-center gap-x-2 text-xs">
  122. <p className="text-foreground-light">
  123. {dayjs(selectedDateRange.period_start.date).format('MMM D, h:mma')}
  124. </p>
  125. <p className="text-foreground-light">
  126. <ArrowRight size={12} />
  127. </p>
  128. <p className="text-foreground-light">
  129. {dayjs(selectedDateRange.period_end.date).format('MMM D, h:mma')}
  130. </p>
  131. </div>
  132. )}
  133. </div>
  134. <ReportFilterBar
  135. filters={filters}
  136. onAddFilter={addFilter}
  137. onRemoveFilters={removeFilters}
  138. isLoading={isLoadingData || isRefetching}
  139. hideDatepicker={true}
  140. datepickerHelpers={datePickerHelpers}
  141. selectedProduct={'postgrest'}
  142. showDatabaseSelector={false}
  143. />
  144. </div>
  145. }
  146. >
  147. <div className="relative mt-8">
  148. <SharedAPIReport
  149. data={data}
  150. error={error}
  151. isLoading={isLoading}
  152. isRefetching={isRefetching}
  153. sql={sql}
  154. />
  155. </div>
  156. </ReportStickyNav>
  157. <div className="py-8">
  158. <ObservabilityLink />
  159. </div>
  160. </>
  161. )
  162. }